package com.linkhub.oms.common.util;

import com.linkhub.oms.common.exception.BizException;
import com.linkhub.oms.common.spring.QtApplicationContextHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * @Description: QtAopUtil
 * @Author: echo
 * @Date: 2021/12/28 15:58
 * @Version: 1.0
 */
@SuppressWarnings("all")
@Slf4j
public class QtAopUtil {

    /**
     * 获取目标类的代理对象
     * <p>
     * 常用于service类的this方法调用
     * </p>
     *
     * @param targetObj targetObj
     * @param <T>       T
     * @return 代理对象
     */
    public static <T> T getProxyObject(T targetObj) {
        try {
            Class<?> objClass = targetObj.getClass();
            if (!AopUtils.isAopProxy(targetObj)) {
                Object bean = QtApplicationContextHelper.getBean(objClass);
                if (Objects.nonNull(bean)) {
                    return (T) bean;
                }
            }

            return targetObj;
        } catch (Exception e) {
            throw new BizException("Error: Get target ProxyObject exception !  Cause:" + e);
        }
    }

    /**
     * 获取源目标对象
     * @see com.baomidou.mybatisplus.extension.toolkit.AopUtils#getTargetObject(Object)
     *
     * @param proxy ignore
     * @param <T>   ignore
     * @return ignore
     */
    public static <T> T getTargetObject(T proxy) {
        if (!AopUtils.isAopProxy(proxy)) {
            return proxy;
        }
        try {
            if (AopUtils.isJdkDynamicProxy(proxy)) {
                return getJdkDynamicProxyTargetObject(proxy);
            } else if (AopUtils.isCglibProxy(proxy)) {
                return getCglibProxyTargetObject(proxy);
            } else {
                log.warn("Warn: The proxy object processing method is not supported.");
                return proxy;
            }
        } catch (Exception e) {
            throw new BizException("Error: Get proxy targetObject exception !  Cause:" + e);
        }
    }

    /**
     * 获取Cglib源目标对象
     *
     * @param proxy ignore
     * @param <T>   ignore
     * @return ignore
     */
    @SuppressWarnings("unchecked")
    private static <T> T getCglibProxyTargetObject(T proxy) throws Exception {
        Field cglibField = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        cglibField.setAccessible(true);
        Object dynamicAdvisedInterceptor = cglibField.get(proxy);
        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);
        Object target = ((org.springframework.aop.framework.AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
        return (T) target;
    }

    /**
     * 获取JdkDynamic源目标对象
     *
     * @param proxy ignore
     * @param <T>   ignore
     * @return ignore
     */
    @SuppressWarnings("unchecked")
    private static <T> T getJdkDynamicProxyTargetObject(T proxy) throws Exception {
        Field jdkDynamicField = proxy.getClass().getSuperclass().getDeclaredField("jdkDynamicField");
        jdkDynamicField.setAccessible(true);
        org.springframework.aop.framework.AopProxy aopProxy = (org.springframework.aop.framework.AopProxy) jdkDynamicField.get(proxy);
        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);
        Object target = ((org.springframework.aop.framework.AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
        return (T) target;
    }
}
